//! 健康检查模块
//! 
//! 提供系统和组件的健康状态监控

use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use tokio::sync::RwLock;
use anyhow::Result;
use tracing::{debug, info, warn, error};

/// 健康状态
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum HealthStatus {
    /// 健康
    Healthy,
    /// 降级（部分功能不可用）
    Degraded,
    /// 不健康
    Unhealthy,
}

impl HealthStatus {
    /// 检查是否健康
    pub fn is_healthy(&self) -> bool {
        matches!(self, HealthStatus::Healthy)
    }

    /// 检查是否可用（健康或降级）
    pub fn is_available(&self) -> bool {
        matches!(self, HealthStatus::Healthy | HealthStatus::Degraded)
    }

    /// 合并多个健康状态
    pub fn merge(statuses: &[HealthStatus]) -> HealthStatus {
        if statuses.is_empty() {
            return HealthStatus::Healthy;
        }

        let mut has_unhealthy = false;
        let mut has_degraded = false;

        for status in statuses {
            match status {
                HealthStatus::Unhealthy => has_unhealthy = true,
                HealthStatus::Degraded => has_degraded = true,
                HealthStatus::Healthy => {}
            }
        }

        if has_unhealthy {
            HealthStatus::Unhealthy
        } else if has_degraded {
            HealthStatus::Degraded
        } else {
            HealthStatus::Healthy
        }
    }
}

/// 组件健康信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComponentHealth {
    /// 组件名称
    pub name: String,
    /// 健康状态
    pub status: HealthStatus,
    /// 状态消息
    pub message: Option<String>,
    /// 检查时间
    pub timestamp: u64,
    /// 响应时间（毫秒）
    pub response_time_ms: Option<f64>,
    /// 详细信息
    pub details: HashMap<String, serde_json::Value>,
}

impl ComponentHealth {
    /// 创建健康的组件状态
    pub fn healthy(name: String) -> Self {
        Self {
            name,
            status: HealthStatus::Healthy,
            message: None,
            timestamp: SystemTime::now()
                .duration_since(UNIX_EPOCH)
                .unwrap()
                .as_secs(),
            response_time_ms: None,
            details: HashMap::new(),
        }
    }

    /// 创建降级的组件状态
    pub fn degraded(name: String, message: String) -> Self {
        Self {
            name,
            status: HealthStatus::Degraded,
            message: Some(message),
            timestamp: SystemTime::now()
                .duration_since(UNIX_EPOCH)
                .unwrap()
                .as_secs(),
            response_time_ms: None,
            details: HashMap::new(),
        }
    }

    /// 创建不健康的组件状态
    pub fn unhealthy(name: String, message: String) -> Self {
        Self {
            name,
            status: HealthStatus::Unhealthy,
            message: Some(message),
            timestamp: SystemTime::now()
                .duration_since(UNIX_EPOCH)
                .unwrap()
                .as_secs(),
            response_time_ms: None,
            details: HashMap::new(),
        }
    }

    /// 设置响应时间
    pub fn with_response_time(mut self, response_time_ms: f64) -> Self {
        self.response_time_ms = Some(response_time_ms);
        self
    }

    /// 添加详细信息
    pub fn with_detail(mut self, key: String, value: serde_json::Value) -> Self {
        self.details.insert(key, value);
        self
    }
}

/// 健康检查trait
#[async_trait]
pub trait HealthCheckProvider: Send + Sync {
    /// 执行健康检查
    async fn check_health(&self) -> Result<ComponentHealth>;
    
    /// 获取检查名称
    fn name(&self) -> &str;
    
    /// 获取检查超时时间
    fn timeout(&self) -> Duration {
        Duration::from_secs(30)
    }
}

/// 健康检查定义
pub struct HealthCheck {
    /// 检查提供者
    provider: Arc<dyn HealthCheckProvider>,
    /// 是否关键检查（影响整体状态）
    critical: bool,
    /// 检查间隔
    interval: Duration,
    /// 最后检查时间
    last_check: Option<SystemTime>,
}

impl HealthCheck {
    /// 创建新的健康检查
    pub fn new(provider: Arc<dyn HealthCheckProvider>, critical: bool) -> Self {
        Self {
            provider,
            critical,
            interval: Duration::from_secs(60),
            last_check: None,
        }
    }

    /// 设置检查间隔
    pub fn with_interval(mut self, interval: Duration) -> Self {
        self.interval = interval;
        self
    }

    /// 检查是否需要执行
    pub fn should_run(&self) -> bool {
        match self.last_check {
            Some(last) => last.elapsed().unwrap_or(Duration::MAX) >= self.interval,
            None => true,
        }
    }

    /// 执行检查
    pub async fn run(&mut self) -> Result<ComponentHealth> {
        let start = SystemTime::now();
        
        let result = tokio::time::timeout(
            self.provider.timeout(),
            self.provider.check_health()
        ).await;

        let response_time = start.elapsed().unwrap_or(Duration::ZERO).as_millis() as f64;
        self.last_check = Some(start);

        match result {
            Ok(Ok(mut health)) => {
                health.response_time_ms = Some(response_time);
                debug!("健康检查完成: {} = {:?}", health.name, health.status);
                Ok(health)
            }
            Ok(Err(e)) => {
                error!("健康检查失败: {} - {}", self.provider.name(), e);
                Ok(ComponentHealth::unhealthy(
                    self.provider.name().to_string(),
                    format!("检查失败: {}", e),
                ).with_response_time(response_time))
            }
            Err(_) => {
                error!("健康检查超时: {}", self.provider.name());
                Ok(ComponentHealth::unhealthy(
                    self.provider.name().to_string(),
                    "检查超时".to_string(),
                ).with_response_time(response_time))
            }
        }
    }

    /// 是否为关键检查
    pub fn is_critical(&self) -> bool {
        self.critical
    }
}

/// 健康检查器
pub struct HealthChecker {
    /// 注册的健康检查
    checks: Arc<RwLock<HashMap<String, HealthCheck>>>,
    /// 最近的检查结果
    results: Arc<RwLock<HashMap<String, ComponentHealth>>>,
}

impl HealthChecker {
    /// 创建新的健康检查器
    pub fn new() -> Self {
        Self {
            checks: Arc::new(RwLock::new(HashMap::new())),
            results: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    /// 注册健康检查
    pub async fn register_check(&self, check: HealthCheck) -> Result<()> {
        let name = check.provider.name().to_string();
        let mut checks = self.checks.write().await;
        checks.insert(name.clone(), check);
        info!("注册健康检查: {}", name);
        Ok(())
    }

    /// 移除健康检查
    pub async fn unregister_check(&self, name: &str) -> Result<()> {
        let mut checks = self.checks.write().await;
        let mut results = self.results.write().await;
        
        checks.remove(name);
        results.remove(name);
        
        info!("移除健康检查: {}", name);
        Ok(())
    }

    /// 运行所有健康检查
    pub async fn run_health_checks(&self) -> Result<()> {
        let mut checks = self.checks.write().await;
        let mut results = self.results.write().await;

        for (name, check) in checks.iter_mut() {
            if check.should_run() {
                match check.run().await {
                    Ok(health) => {
                        results.insert(name.clone(), health);
                    }
                    Err(e) => {
                        error!("健康检查执行失败: {} - {}", name, e);
                        results.insert(name.clone(), ComponentHealth::unhealthy(
                            name.clone(),
                            format!("执行失败: {}", e),
                        ));
                    }
                }
            }
        }

        debug!("健康检查运行完成，共 {} 个检查", results.len());
        Ok(())
    }

    /// 获取整体健康状态
    pub async fn get_overall_status(&self) -> Result<HealthStatus> {
        let results = self.results.read().await;
        let checks = self.checks.read().await;

        if results.is_empty() {
            return Ok(HealthStatus::Healthy);
        }

        let mut critical_statuses = Vec::new();
        let mut all_statuses = Vec::new();

        for (name, result) in results.iter() {
            all_statuses.push(result.status.clone());
            
            if let Some(check) = checks.get(name) {
                if check.is_critical() {
                    critical_statuses.push(result.status.clone());
                }
            }
        }

        // 如果有关键检查，优先考虑关键检查的状态
        let status = if !critical_statuses.is_empty() {
            HealthStatus::merge(&critical_statuses)
        } else {
            HealthStatus::merge(&all_statuses)
        };

        debug!("整体健康状态: {:?}", status);
        Ok(status)
    }

    /// 获取所有组件健康状态
    pub async fn get_component_health(&self) -> Result<Vec<ComponentHealth>> {
        let results = self.results.read().await;
        Ok(results.values().cloned().collect())
    }

    /// 获取指定组件的健康状态
    pub async fn get_health(&self, name: &str) -> Result<Option<ComponentHealth>> {
        let results = self.results.read().await;
        Ok(results.get(name).cloned())
    }

    /// 获取健康检查数量
    pub async fn check_count(&self) -> usize {
        let checks = self.checks.read().await;
        checks.len()
    }
}

impl Default for HealthChecker {
    fn default() -> Self {
        Self::new()
    }
}

/// 简单的健康检查提供者（用于测试）
pub struct SimpleHealthCheck {
    name: String,
    status: HealthStatus,
    message: Option<String>,
}

impl SimpleHealthCheck {
    pub fn new(name: String, status: HealthStatus) -> Self {
        Self {
            name,
            status,
            message: None,
        }
    }

    pub fn with_message(mut self, message: String) -> Self {
        self.message = Some(message);
        self
    }
}

#[async_trait]
impl HealthCheckProvider for SimpleHealthCheck {
    async fn check_health(&self) -> Result<ComponentHealth> {
        let health = match self.status {
            HealthStatus::Healthy => ComponentHealth::healthy(self.name.clone()),
            HealthStatus::Degraded => ComponentHealth::degraded(
                self.name.clone(),
                self.message.clone().unwrap_or_else(|| "服务降级".to_string()),
            ),
            HealthStatus::Unhealthy => ComponentHealth::unhealthy(
                self.name.clone(),
                self.message.clone().unwrap_or_else(|| "服务不可用".to_string()),
            ),
        };
        
        Ok(health)
    }

    fn name(&self) -> &str {
        &self.name
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_health_status_merge() {
        assert_eq!(HealthStatus::merge(&[]), HealthStatus::Healthy);
        
        assert_eq!(
            HealthStatus::merge(&[HealthStatus::Healthy, HealthStatus::Healthy]),
            HealthStatus::Healthy
        );
        
        assert_eq!(
            HealthStatus::merge(&[HealthStatus::Healthy, HealthStatus::Degraded]),
            HealthStatus::Degraded
        );
        
        assert_eq!(
            HealthStatus::merge(&[HealthStatus::Healthy, HealthStatus::Unhealthy]),
            HealthStatus::Unhealthy
        );
        
        assert_eq!(
            HealthStatus::merge(&[HealthStatus::Degraded, HealthStatus::Unhealthy]),
            HealthStatus::Unhealthy
        );
    }

    #[test]
    fn test_component_health_creation() {
        let healthy = ComponentHealth::healthy("test".to_string());
        assert_eq!(healthy.status, HealthStatus::Healthy);
        assert!(healthy.message.is_none());
        
        let degraded = ComponentHealth::degraded("test".to_string(), "warning".to_string());
        assert_eq!(degraded.status, HealthStatus::Degraded);
        assert_eq!(degraded.message, Some("warning".to_string()));
        
        let unhealthy = ComponentHealth::unhealthy("test".to_string(), "error".to_string());
        assert_eq!(unhealthy.status, HealthStatus::Unhealthy);
        assert_eq!(unhealthy.message, Some("error".to_string()));
    }

    #[tokio::test]
    async fn test_health_checker() {
        let checker = HealthChecker::new();
        
        // 注册健康检查
        let provider = Arc::new(SimpleHealthCheck::new("test".to_string(), HealthStatus::Healthy));
        let check = HealthCheck::new(provider, true);
        checker.register_check(check).await.unwrap();
        
        assert_eq!(checker.check_count().await, 1);
        
        // 运行检查
        checker.run_health_checks().await.unwrap();
        
        // 验证结果
        let status = checker.get_overall_status().await.unwrap();
        assert_eq!(status, HealthStatus::Healthy);
        
        let health = checker.get_health("test").await.unwrap();
        assert!(health.is_some());
        assert_eq!(health.unwrap().status, HealthStatus::Healthy);
    }

    #[tokio::test]
    async fn test_critical_vs_non_critical_checks() {
        let checker = HealthChecker::new();
        
        // 注册关键检查（不健康）
        let critical_provider = Arc::new(SimpleHealthCheck::new("critical".to_string(), HealthStatus::Unhealthy));
        let critical_check = HealthCheck::new(critical_provider, true);
        checker.register_check(critical_check).await.unwrap();
        
        // 注册非关键检查（健康）
        let non_critical_provider = Arc::new(SimpleHealthCheck::new("non_critical".to_string(), HealthStatus::Healthy));
        let non_critical_check = HealthCheck::new(non_critical_provider, false);
        checker.register_check(non_critical_check).await.unwrap();
        
        // 运行检查
        checker.run_health_checks().await.unwrap();
        
        // 整体状态应该是不健康（因为关键检查失败）
        let status = checker.get_overall_status().await.unwrap();
        assert_eq!(status, HealthStatus::Unhealthy);
    }
}
